#ifndef STEINER_STEINER_POINT_H
#define STEINER_STEINER_POINT_H

#include <list>
#include <map>
#include "Point2D.h"
#include "MergePoint.h"
#include "Arithmetic.h"

namespace STEINER {

template <typename T>
class SteinerPoint : public Point2D<T>
{
public:
    using MergePointSPtr = std::shared_ptr<MergePoint<T> >;
    using MergePointWPtr = std::weak_ptr<MergePoint<T> >;
    using SteinerPointSPtr = std::shared_ptr<SteinerPoint<T> >;

    SteinerPoint() {}
    SteinerPoint(const T _x, const T _y) : Point2D<T>(_x, _y) {}
    ~SteinerPoint() {}

    bool operator==(const SteinerPoint& that) const {
        return static_cast<Point2D<T> >(*this) == static_cast<Point2D<T> >(that);
    }

    bool operator<(const SteinerPoint& that) const {
        return static_cast<Point2D<T> >(*this) < static_cast<Point2D<T> >(that);
    }

    static SteinerPointSPtr CalSteinerPoint(const MergePointSPtr& a, const MergePointSPtr& b) {
        if (nullptr == a || nullptr == b) {
            return nullptr;
        }
        T x = GetMid(0, 0, a->GetX(), b->GetX());
        T y = GetMid(0, 0, a->GetY(), b->GetY());
        if (0 == x && 0 == y) {
            return nullptr;
        }
        SteinerPointSPtr ret = std::make_shared<SteinerPoint>(x, y);
        ret->AddParent(a);
        ret->AddParent(b);
        return ret;
    }

    bool AddParent(const MergePointSPtr& parent) {
        for (const auto p : parents) {
            auto sp = p.lock();
            if (nullptr != sp && *sp == *parent) {
                return false;
            }
        }
        parents.emplace_back(parent);
        return true;
    }

    std::list<MergePointWPtr> GetParents() const {
        return parents;
    }

    T GetLengthOfParents() const {
        std::list<std::pair<T, T> > coords;
        for (const auto p : parents) {
            auto sp = p.lock();
            if (nullptr != sp) {
                coords.emplace_back(std::make_pair(p->GetX(), p->GetY()));
            }
        }
        return GetManhattan(Point2D<T>::x, Point2D<T>::y, coords);
    }


protected:
    std::list<MergePointWPtr> parents;

};

template <typename T>
struct CompareSteinerPointK {
    bool operator()(const std::shared_ptr<SteinerPoint<T> >& left, const std::shared_ptr<SteinerPoint<T> >& right) const {
        return *left < *right;
    }
};

}
#endif
